/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ola_service.h"
#include "ola_sdk.h"
#include "ola_def.h"
#include "ola_log.h"
#include "ola_error.h"
#include "ola_base_utils.h"
#include "ola_sdk_api.h"
#include "ola_coap_net.h"
#include "ola_link.h"
#include "securec.h"
#include "cJSON.h"

/* 消息数据增加错误码 */
static int BuildDevicePropertiesResponse(const OlaData *inData, int errorCode, OlaData *outData)
{
    char *payload = NULL;
    cJSON *json = NULL;

    if ((inData == NULL) || (inData->data == NULL) || (inData->len == 0) || (outData == NULL)) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    do {
        json = cJSON_Parse((const char *)inData->data);
        if (json == NULL) {
            OlaLogError("json parse error");
            return OLA_ERROR;
        }

        if (cJSON_AddNumberToObject(json, OLA_STRING_ERRCODE, errorCode) == NULL) {
            OlaLogError("add number error");
            break;
        }

        payload = cJSON_PrintUnformatted(json);
        if (payload == NULL) {
            OlaLogError("get json payload error");
            break;
        }
        outData->data = (unsigned char *)payload;
        outData->len = strlen(payload);
        cJSON_Delete(json);
        return OLA_OK;
    } while (0);

    cJSON_Delete(json);
    return OLA_ERROR;
}

int OlaQueryDeviceProperties(OlaCoapSession *ses, const OlaCoapPacket *pkt, OlaData *outData, OlaReqId reqId)
{
    int ret;
    OlaData inData = {NULL, 0};
    OlaData payload = {NULL, 0};

    if ((ses == NULL) || (pkt == NULL) || (outData == NULL)) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    if ((pkt->payload.data == NULL) || (pkt->payload.len == 0)) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    ret = OlaQueryDeviceService(&(pkt->payload), &inData);
    if (ret != OLA_OK) {
        OlaLogError("query error:%d", ret);
        return ret;
    }

    ret = BuildDevicePropertiesResponse(&inData, ret, &payload);
    if (ret != OLA_OK) {
        OlaLogError("build outdata error");
        OlaDataFree(&inData);
        return ret;
    }
    outData->data = payload.data;
    outData->len = payload.len;
    OlaDataFree(&inData);
    return OLA_OK;
}

int OlaControlDeviceProperties(OlaCoapSession *ses, const OlaCoapPacket *pkt, OlaData *outData, OlaReqId reqId)
{
    int ret;
    OlaData inData = {NULL, 0};
    OlaData payload = {NULL, 0};

    if ((ses == NULL) || (pkt == NULL) || (reqId == NULL) || (outData == NULL)) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    if ((pkt->payload.data == NULL) || (pkt->payload.len == 0)) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    ret = OlaCtrlDeviceService(&(pkt->payload), reqId);
    if (ret != OLA_OK) {
        OlaLogError("control result:%d", ret);
        return ret;
    }

    ret = OlaQueryDeviceService(&(pkt->payload), &inData);
    if (ret != OLA_OK) {
        OlaLogError("query error:%d", ret);
        return ret;
    }

    ret = BuildDevicePropertiesResponse(&inData, ret, &payload);
    if (ret != OLA_OK) {
        OlaLogError("build outdata error");
        OlaDataFree(&inData);
        return ret;
    }
    outData->data = payload.data;
    outData->len = payload.len;
    OlaDataFree(&inData);
    return OLA_OK;
}

#ifdef OLA_DEMO_TEST
static void CoapDevicePropertiesHandler(OlaCoapSession *session, const OlaCoapPacket *pkt)
{
    if ((session == NULL) || (pkt == NULL) || !OlaIsValidCloudSession(session)) {
        OlaLogWarning("invalid param");
        return;
    }
    if (pkt->header.code != OLA_COAP_RESPONSE_CODE_CONTENT) {
        OlaLogWarning("report device properties error[%d]", pkt->header.code);
    } else {
        OlaLogInfo("report device properties success");
    }
    return;
}
#endif

int OlaReportDeviceProperties(const OlaData *json, OlaReqId id)
{
    int ret;
    OlaCoapParam param;
    OlaData payload = {NULL, 0};

    if (json == NULL) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }

    (void)memset_s(&param, sizeof(OlaCoapParam), 0, sizeof(OlaCoapParam));
    if (id == NULL) {
#ifdef OLA_DEMO_TEST
        /* 打桩代码，设备属性上报，处理云侧返回 */
        OlaBuildCloudRequestCoapParam(&param, OLA_COAP_URI_PROPERTIES_REPORT, CoapDevicePropertiesHandler, true);
#else
        OlaBuildCloudRequestCoapParam(&param, OLA_COAP_URI_PROPERTIES_REPORT, NULL, true);
#endif
        ret = OlaSendDataToCloud(json, &param);
    } else {
        param.reqId = id;
        ret = BuildDevicePropertiesResponse(json, 0, &payload); /* 0表示异步执行成功 */
        if (ret != OLA_OK) {
            OlaLogError("build outdata error");
            return ret;
        }
        ret = OlaSendDataToCloud(&payload, &param);
        OlaDataFree(&payload);
    }

    if (ret != OLA_OK) {
        OlaLogError("send data error");
    }
    return ret;
}
/* services  消息处理函数 */
int OlaGetServiceHandler(OlaCoapSession *session, const OlaCoapPacket *pkt, OlaData *outData, OlaReqId reqId)
{
    if ((session == NULL) || (pkt == NULL) || (outData == NULL)) {
        OlaLogError("invalid param");
        return OLA_COM_ERR_INVALID_ARGUMENT;
    }
    (void)session;
    (void)reqId;
    if (OlaGetDeviceData(OLA_DATA_TYPE_JSON_DEVICE_MODEL, outData) != OLA_OK) {
        OlaLogError("get outside device model failed");
        return OLA_ERROR;
    }
    if ((outData->len == 0) || (outData->data == NULL)) {
        OlaLogError("invalid model data");
        return OLA_ERROR;
    }
    return OLA_OK;
}
